package test.demo;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import tech.waterism.modelbase.PredictBase;
import tech.waterism.modelbase.PredictResult;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * SCS-CN
 *
 * @author 初京刚
 * @version 1.0
 */

public class SCS_CN extends PredictBase {

    /**
     * 当前土壤类型、土壤覆被下水分条件II（一般湿润）时的SCS曲线数（Curve Number）
     */
    private double CN2;

    /**
     * 前期土壤水分条件（1-干燥，2-一般湿润，3-湿润）
     */
    private int AMC;

    /**
     * 流域平均坡度，%
     */
    private double slp;

    /**
     * 降水量
     */
    private double[] floodDrp;

    /**
     * 降水时间
     */
    private Date[] floodTm;


    /**
     * 预报开始时间
     */
    private Date startTm;

    /**
     * 预报开始数组下标
     */
    private int startIndex;

    /**
     * 降水序列长度
     */
    private Integer floodRainRange;

    /**
     * 降水时段长
     */
    private double timeInterval;

    /**
     * 模拟总产流
     */
    private double[] RunoffSim;

    public SCS_CN(Map<String, String> data) {
        super();
        CN2 = Double.parseDouble(data.get("CN2"));
        slp = Double.parseDouble(data.get("SLOPE"));
        AMC = Integer.parseInt(data.get("AMC"));
        floodTm = JSON.parseObject(data.get("dt"), Date[].class);               // input[i].data.dt
        startTm = JSON.parseObject(data.get("start"), Date.class);
        startIndex = ArrayUtil.indexOf(floodTm, startTm);
        floodTm = JSON.parseObject(data.get("dt"), Date[].class);   // input[i].data.dt
        floodDrp = JSON.parseObject(data.get("rain"), double[].class);// input[i].data.rain
        floodRainRange = floodDrp.length;
        if (floodTm.length > 1) {
            timeInterval = getHours(floodTm[0], floodTm[1]);
        } else {
            timeInterval = Double.parseDouble(data.get("clen"));                  // index.clen
        }
        RunoffSim = new double[floodRainRange];
    }

    /**
     * 模型计算
     */
    public Map<String, double[]> SCSmodel() {

        // SCS产流
        SCS();

        Map<String, double[]> simulationResult = new HashMap<>();
        simulationResult.put("runoffSim", RunoffSim);
        simulationResult.put("rain", floodDrp);
        return simulationResult;
    }

    /**
     * SCS产流模型
     */
    private void SCS() {
        double CN2S, CN1, CN3, CN, S, Ia;
        CN1 = CN2 - 20 * (100 - CN2) / (100 - CN2 + Math.exp(2.533 - 0.0636 * (100 - CN2)));
        CN3 = CN2 * Math.exp(0.00673 * (100 - CN2));
        CN2S = (CN3 - CN2) / 3 * (1 - 2 * Math.exp(-13.86 * slp)) + CN2;
        CN = CN2S;
        if(AMC == 1) {
            CN = CN2S - 20 * (100 - CN2S) / (100 - CN2S + Math.exp(2.533 - 0.0636 * (100 - CN2S)));
        } else if(AMC == 3) {
            CN = CN2S * Math.exp(0.00673 * (100 - CN2S));
        }
        S = 25400 / CN - 254;
        Ia = 0.2 * S;
        for (int i = 0; i < floodRainRange; i++) {
            if(floodDrp[i] > Ia) {
                RunoffSim[i] = Math.pow((floodDrp[i] - Ia), 2) / (floodDrp[i] + 0.8 * S);
            } else {
                RunoffSim[i] = 0.0;
            }
        }
    }

    private int getHours(Date dt_beg, Date dt_end) {
        int hours = -1;
        hours = Long.valueOf((dt_end.getTime() - dt_beg.getTime()) / (3600 * 1000L)).intValue();
        return hours;
    }

    @Override
    public void init() {

    }

    @Override
    public PredictResult predict() {
        PredictResult result = new PredictResult();
        Map<String, double[]> map = SCSmodel();

        result.setRunoffSim(map.get("runoffSim"));
        return result;
    }
}